#include <stdio.h>
#include <stdint.h>

#ifndef __SIZE_T
#define __SIZE_T
typedef unsigned int size_t;
#endif

int main(int argc, char **argv) 
{
    int num = 0;
    int *pi = &num;

    printf("Address of num: %d Value: %d\n", &num, num);
    printf("Address of pi: %d Value: %d\n", &pi, pi);
    printf("Address of pi: %x Value: %x\n", &pi, pi);
    printf("Address of pi: %o Value: %o\n", &pi, pi);
    printf("Address of pi: %p Value: %p\n", &pi, pi);

    size_t sizet = -5;
    printf("%d\n", sizet);
    printf("%zu\n",sizet);

    sizet = 5;
    printf("%d\n", sizet);
    printf("%zu\n", sizet);

    printf("Size of *char: %d\n", sizeof(char*));

    //使用intptr_t 和 uintptr_t
    //它们提供了一种可移植且安全的方法声明指针
    //内核中通常的内存地址常常是unsigned long，
    //利用了指针和长整型一直是相同大小这个事实
    int numb;
    intptr_t *pi1 = &numb;
    uintptr_t *pu1 = &numb;

    //指针的算术运算
    printf("Size of *int: %d\n", sizeof(int*));
    int vector[] = {28, 41, 7};
    int *pi2 = vector;
    printf("Address: %d And Value: %d\n",pi2, *pi2);
    pi2 += 1;
    printf("Address: %d And Value: %d\n",pi2, *pi2);
    pi2 += 1;
    printf("Address: %d And Value: %d\n",pi2, *pi2);

    short s;
    short *ps = &s;
    char c;
    char *pc = &c;
    printf("Content of ps before: %d\n",ps);
    ps = ps + 1;
    printf("Content of ps after: %d\n", ps);
    printf("Content of pc before: %d\n", pc);
    pc = pc + 1;
    printf("Content of pc after:%d\n", pc);

    //void指针和加法
    int num1 = 5;
    void *pv = &num1;
    printf("%p\n", pv);
    pv = pv + 1;
    printf("%p\n", pv);

    //指针相减
    //ptrdiff_t类型表示两个指针差值的可移植方式
    //指针相减的结果以ptrdiff_t类型返回
    //因为指针长度可能不同，这个类型简化了处理差值的任务
    int *p0 = vector;
    int *p1 = vector + 1;
    int *p2 = vector + 2;

    printf("p2-p0: %d and p2: %d and p0: %d\n", p2-p0, p2, p0);   //p2-p0:2
    printf("p2-p1: %d and p2: %d and p1: %d\n", p2-p1, p2, p1);   //p2-p1:1
    printf("p0-p1: %d and p0: %d and p1: %d\n", p0-p1, p0, p1);   //p0-p1:-1 

    printf("*p0-*p1: %d\n", *p0-*p1);   //*p0-*p1: -13

    //比较指针
    printf("p2>p0: %d\n", p2>p0);   //p2>p0:1
    printf("p2<p0: %d\n", p2<p0);   //p2<p0:0
    printf("p0>p1: %d\n", p0>p1);   //p0>01:0

    //多层间接引用
    char *titles[] = {
        "A Tale of Two Cities",
        "Wuthering Heights",
        "Don Quixote",
        "Odyssey",
        "Moby-Dick",
        "Hamlet",
        "Gulliver's Travels"
    };
    char **bestBooks[3];
    char **englishBooks[4];

    bestBooks[0] = &titles[0];
    bestBooks[1] = &titles[3];
    bestBooks[2] = &titles[5];

    englishBooks[0] = &titles[0];
    englishBooks[1] = &titles[1];
    englishBooks[2] = &titles[5];
    englishBooks[3] = &titles[6];

    printf("%s\n", *englishBooks[1]);   //Wuthering Heights

    //指向常量的指针
    //pci可以被修改为指向不同的整数常量
    //pci可以被修改为指向不同的非整数常量
    //可以解引pci以读取数据
    //不能解引pci从而修改它指向的数据
    const int *pci;

    //指向非常量的常量指针
    //指针不可变，但它指向的数据可变
    //cpi必须被初始化为指向非常量变量
    //cpi不能被修改
    //cpi指向的数据可以被修改
    int num3;
    int *const cpi = &num3;

    const int limit = 500;
    int *const cpi1 = &limit;

    //指向常量的常量指针
    const int *const cpci = &limit;
    
    //指向“指向常量的常量指针”的指针
    const int *const *pcpci = &cpci;

    printf("%d\n", *cpci);
    //pcpci = &cpci;
    printf("%d\n", **pcpci);

    //指针类型              指针是否可修改      指向指针的数据是否可修改
    //指向非常量的指针          是              是
    //指向常量的指针            是              否
    //指向非常量的常量指针       否              是
    //指向常量的常量指针        否              否

    return 0;
}
